/**
 * @file deepseek_api.c
 * @brief DeepSeek API 流式对话接口实现
 */
#include "define_config.h"
 #include "deepseek_api.h"
 #include "cJSON.h"
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdatomic.h>
 #include <time.h>
 #include <signal.h>
 #include <stdbool.h>
 #include <unistd.h>
 #include <sys/time.h>
#include <linux/time.h>
 //-----------------------------------------------------------------------------
 // 内部类型定义
 //-----------------------------------------------------------------------------
 
 /**
  * @brief 流式处理上下文（线程安全）
  */
 typedef struct {
     DS_StreamCallback user_callback;  // 用户回调函数
     char*             buffer;         // 动态缓冲区（环形结构）
     size_t            buffer_size;    // 缓冲区总容量
     size_t            head;           // 有效数据起始位置
     size_t            tail;           // 有效数据结束位置
     atomic_bool       is_active;      // 上下文激活状态
 } StreamContext;
 
 /**
  * @brief HTTP请求关联的完整上下文
  */
 typedef struct {
     char*           auth_header;    // "Authorization: Bearer ..." 头
     char*           request_body;   // JSON请求体
     StreamContext*  stream_ctx;     // 流处理上下文
 } RequestContext;
 
 //-----------------------------------------------------------------------------
 // 静态函数声明
 //-----------------------------------------------------------------------------
 
 static size_t     stream_adapter(void* ptr, size_t size, size_t nmemb, void* userdata);
 static bool       parse_sse_event(StreamContext* ctx, const char* event);
 static void       cleanup_request_context(RequestContext* ctx);
 
 //-----------------------------------------------------------------------------
 // 公开接口实现
 //-----------------------------------------------------------------------------
 
 /**
  * @brief 发送标准流式API请求
  * @param api_key API认证密钥（需至少10字符）
  * @param prompt 用户输入的对话内容
  * @param model 指定使用的AI模型
  * @param callback 流式数据回调函数
  * @return bool 请求是否成功发起
  * 
  * 功能流程：
  * 1. 参数有效性校验
  * 2. 资源分配与上下文构建
  * 3. 构造HTTP请求要素
  * 4. 发起异步HTTP请求
  * 5. 资源回收与错误处理
  */
 bool DS_SendStandardRequest(
     const char* api_key,
     const char* prompt,
     const char* model,
     DS_StreamCallback callback
 ) {
     // 参数校验
    if (!api_key || strlen(api_key) < 10 || !prompt || !model || !callback) {
        fprintf(stderr, "[DS] 无效的输入参数\n");
        return false;
    }
     // 创建请求上下文
     RequestContext* req_ctx = calloc(1, sizeof(RequestContext));
     if (!req_ctx) {
         fprintf(stderr, "[DS] 内存分配失败\n");
         return false;
     }
 
     //---------------------------------------
     // 构建认证头（Bearer Token）
     //---------------------------------------
     req_ctx->auth_header = malloc(256);
     if (!req_ctx->auth_header) goto error_cleanup;
     snprintf(req_ctx->auth_header, 256, "Authorization: Bearer %s", api_key); // 安全格式化
 
     //---------------------------------------
     // 初始化流式处理上下文（环形缓冲区）
     //---------------------------------------
     req_ctx->stream_ctx = malloc(sizeof(StreamContext));
     if (!req_ctx->stream_ctx) goto error_cleanup;
     
     *req_ctx->stream_ctx = (StreamContext){
         .user_callback = callback,
         .buffer_size   = 4096,       // 4KB环形缓冲区
         .buffer        = malloc(4096),
         .head          = 0,          // 读指针
         .tail          = 0,          // 写指针
         .is_active     = ATOMIC_VAR_INIT(true) // 原子状态标志
     };
     if (!req_ctx->stream_ctx->buffer) goto error_cleanup;
 
     //---------------------------------------
     // 构建JSON请求体（SSE规范）
     //---------------------------------------
     cJSON* root = cJSON_CreateObject();
     cJSON_AddStringToObject(root, "model", model);  // 动态模型参数
     cJSON_AddBoolToObject(root, "stream", true);    // 强制流式模式
 
     cJSON* messages = cJSON_AddArrayToObject(root, "messages");
     
     // 系统预设角色消息
     cJSON* system_msg = cJSON_CreateObject();
     cJSON_AddStringToObject(system_msg, "role", "system");
     cJSON_AddStringToObject(system_msg, "content", "你是DeepSeek开发的人工智能助手");
     cJSON_AddItemToArray(messages, system_msg);
 
     // 用户消息封装
     cJSON* user_msg = cJSON_CreateObject();
     cJSON_AddStringToObject(user_msg, "role", "user");
     cJSON_AddStringToObject(user_msg, "content", prompt);
     cJSON_AddItemToArray(messages, user_msg);
 
     req_ctx->request_body = cJSON_PrintUnformatted(root); // 紧凑JSON格式
     cJSON_Delete(root);
     if (!req_ctx->request_body) goto error_cleanup;
 
     //---------------------------------------
     // 配置HTTP请求参数（CURL兼容）
     //---------------------------------------
     const char* headers[] = {
         "Content-Type: application/json",  // 标准JSON头
         req_ctx->auth_header,              // 认证头
         NULL
     };
 
     HTTP_RequestConfig config = {
         .method         = HTTP_POST,
         .url            = DEEPSEEK_API_URL,
         .headers        = headers,
         .request_body   = req_ctx->request_body,
         .body_size      = strlen(req_ctx->request_body),
     };
 
     //---------------------------------------
     // 发送异步HTTP请求（非阻塞）
     //---------------------------------------
     HTTP_Status status = HTTP_SendRequest(&config, stream_adapter, req_ctx->stream_ctx);
     
     //---------------------------------------
     // 请求结果初步处理
     //---------------------------------------
     if (status != HTTP_OK) {
         fprintf(stderr, "[DS] 请求失败，状态码：%d\n", status);
         goto error_cleanup;
     }
 
     return true;
 
 error_cleanup:
     cleanup_request_context(req_ctx);
     return false;
 }
 
 //-----------------------------------------------------------------------------
 // 内部工具函数实现
 //-----------------------------------------------------------------------------
 
 /**
  * @brief 流式数据适配器（CURL回调函数）
  * @param ptr 接收到的数据块指针
  * @param size 数据块单位大小
  * @param nmemb 数据块数量
  * @param userdata 流处理上下文指针
  * @return size_t 实际处理的数据量
  * 
  * 核心功能：
  * 1. 接收数据块写入环形缓冲区
  * 2. 动态维护缓冲区读写指针
  * 3. 解析SSE事件流协议
  * 4. 错误检测与状态控制
  */
 static size_t stream_adapter(
     void* ptr, 
     size_t size, 
     size_t nmemb, 
     void* userdata
 ) {
     StreamContext* ctx = (StreamContext*)userdata;
     // 上下文有效性检查（原子状态检测）
     if (!ctx || !atomic_load(&ctx->is_active)) return 0;
 
     const char* data = (const char*)ptr;
     const size_t data_len = size * nmemb;  // 计算总数据长度
 
     //---------------------------------------
     // 环形缓冲区写入
     //---------------------------------------
     size_t free_space = ctx->buffer_size - ctx->tail;
     if (data_len > free_space) {
         // 缓冲区整理：移动有效数据到头部
         memmove(ctx->buffer, ctx->buffer + ctx->head, ctx->tail - ctx->head);
         ctx->tail -= ctx->head;  // 更新尾指针
         ctx->head = 0;           // 头指针复位
         free_space = ctx->buffer_size - ctx->tail;  // 重新计算可用空间
     }
 
     // 溢出保护（当数据超过缓冲区容量时）
     if (data_len > free_space) {
         fprintf(stderr, "[DS] 缓冲区溢出，丢弃 %zu 字节\n", data_len - free_space);
         return 0;  // 返回0会终止CURL传输
     }
 
     // 安全写入数据
     memcpy(ctx->buffer + ctx->tail, data, data_len);
     ctx->tail += data_len;  // 更新尾指针
 
     //---------------------------------------
     // 逐行解析SSE事件
     //---------------------------------------
     while (ctx->head < ctx->tail) {
         char* start = ctx->buffer + ctx->head;
         char* end = memchr(start, '\n', ctx->tail - ctx->head);
         if (!end) break;  // 未找到换行符时暂停解析
 
         *end = '\0'; // 临时终止符（用于字符串处理）
         
         // 检测SSE数据前缀（"data: "）
         if (strncmp(start, "data: ", 6) == 0) {
             // 解析失败时关闭上下文
             if (!parse_sse_event(ctx, start + 6)) {
                 atomic_store(&ctx->is_active, false);  // 原子状态更新
                 break;
             }
         }
         
         ctx->head = end - ctx->buffer + 1; // 移动头指针跳过已处理数据
     }
 
     return data_len;  // 必须返回原始数据长度（避免CURL重试）
 }
 
 /**
  * @brief 解析单个SSE事件
  */
 /**
  * @brief 解析SSE事件数据
  * @param ctx 流处理上下文
  * @param event SSE原始事件字符串
  * @return bool 是否继续处理后续事件
  * 
  * 解析流程：
  * 1. 原始JSON解析
  * 2. 错误响应检测
  * 3. 数据结构有效性验证
  * 4. 内容提取与回调触发
  */
 static bool parse_sse_event(StreamContext* ctx, const char* event) {
    // 处理流式结束标记  
    if (strcmp(event, "[DONE]") == 0) 
    {   
        DEBUG_LOG("收到流式结束标记");
        return true;
    }
     // 原始JSON解析（失败时记录原始数据）
     cJSON* root = cJSON_Parse(event);
     if (!root) {
         fprintf(stderr, "[DS] JSON解析失败: %s\n", event);
         return false;
     }
 
     // 错误响应优先处理（服务器返回4xx/5xx错误）
     cJSON* error = cJSON_GetObjectItem(root, "error");
     if (error) {
         cJSON* message = cJSON_GetObjectItem(error, "message");
         fprintf(stderr, "[DS] 服务器错误: %s\n", 
                 message ? message->valuestring : "未知错误");
         cJSON_Delete(root);
         return false;  // 严重错误需终止处理
     }
 
     // 验证响应结构（必须包含非空choices数组）
     cJSON* choices = cJSON_GetObjectItem(root, "choices");
     if (!cJSON_IsArray(choices) || cJSON_GetArraySize(choices) == 0) {
         fprintf(stderr, "[DS] 无效的响应结构\n");
         cJSON_Delete(root);
         return false;
     }
 
     // 提取首个对话选项（标准SSE格式）
     cJSON* choice = cJSON_GetArrayItem(choices, 0);
     cJSON* delta = cJSON_GetObjectItem(choice, "delta");  // 流式增量数据
     if (!delta) {
         fprintf(stderr, "[DS] 缺少delta字段\n");
         cJSON_Delete(root);
         return false;
     }
 
     // 获取内容片段（可能为空中间事件）
     cJSON* content = cJSON_GetObjectItem(delta, "content");
     if (!cJSON_IsString(content)) {
         cJSON_Delete(root);
         return true; // 非错误状态，继续处理后续事件
     }
 
     // 传递内容给上层回调（最终内容累积由用户处理）
     if (ctx->user_callback) {
         ctx->user_callback(content->valuestring, strlen(content->valuestring));
     }
 
     cJSON_Delete(root);  // 释放JSON树内存
     return true;
 }
 
 /**
  * @brief 清理请求上下文及其所有关联资源
  * @param ctx 要清理的请求上下文指针
  * 
  * 资源释放顺序：
  * 1. 流处理上下文及其缓冲区（最深层资源）
  * 2. HTTP相关资源（认证头、请求体）
  * 3. 上下文结构体自身
  * 
  * 安全特性：
  * - 空指针安全检查
  * - 双重释放防护
  * - 资源彻底释放
  */
 static void cleanup_request_context(RequestContext* ctx) {
     if (!ctx) return;  // 空指针防御
  
     // 清理流式处理上下文（LIFO顺序）
     if (ctx->stream_ctx) {
         free(ctx->stream_ctx->buffer);  // 释放环形缓冲区
         free(ctx->stream_ctx);          // 释放流上下文结构体
     }
  
     // 释放HTTP相关资源（申请顺序逆序）
     free(ctx->auth_header);   // 认证头字符串
     free(ctx->request_body);  // JSON请求体字符串
  
     // 最后释放上下文自身（确保其他资源已释放）
     free(ctx);  // 释放主上下文结构体
 }



 // 增强型流回调（支持中断检测）
 /**
  * @brief 流式响应回调函数
  * @param text 接收到的文本数据指针
  * @param len 数据长度（字节数）
  * 
  * 核心功能：
  * 1. 实时处理API流式响应数据
  * 2. 首块数据预处理（清除等待动画）
  * 3. 安全字符过滤（ASCII 32以上字符）
  * 4. 响应内容格式化输出
  * 
  * 注意事项：
  * - 使用静态变量保持首块数据状态
  * - 严格过滤控制字符保证终端安全
  * - 支持实时响应中断请求
  */
 void stream_callback(const char *text, size_t len) {
    static bool is_first_chunk = true;  // 首块数据标识（跨调用保持状态）
    
    // 安全过滤：中断/空数据/空指针三种无效情况
    if (g_interrupted || len == 0 || !text) return;

    // 首块数据处理流程
    if (is_first_chunk) {
        printf("\r\033[K"); // ANSI转义序列：\r回到行首，\033[K清除整行
        INFO_LOG("开始接收响应：");
        is_first_chunk = false;  // 状态标识更新
    }

    /* 安全输出过滤：
     * - 换行符转换为带提示符的新行
     * - 仅输出可打印字符和制表符
     * - 过滤所有控制字符（ASCII < 32）
     */
    for (size_t i = 0; i < len; ++i) {
        if (text[i] == '\n') printf("\n  >> ");   // 格式化换行
        else if (text[i] >= 32 || text[i] == '\t') putchar(text[i]); // 安全字符
    }
    fflush(stdout);  // 强制立即输出（避免缓冲区延迟）
}

 // 执行请求带重试机制
 /**
  * @brief 带指数退避的重试请求执行器
  * @param api_key DeepSeek API密钥
  * @param question 要发送的问题内容
  * @return bool 最终请求是否成功
  * 
  * 重试策略：
  * 1. 指数退避算法：延迟时间 = BASE_DELAY * 2^retries
  * 2. 最大重试次数限制（MAX_RETRIES）
  * 3. 实时响应中断请求
  * 
  * 监控机制：
  * - 记录每次请求的精确开始时间
  * - 实时更新全局中断状态
  * - 计算精确的等待耗时
  */
 static bool execute_request_with_retry(const char* api_key, const char* question,const char* mode) {
    int retries = 0;        // 当前重试次数
    bool success = false;   // 请求成功标识
    do {
        // 记录请求开始时间（用于超时计算）
        clock_gettime(CLOCK_MONOTONIC, &g_request_start_time);

        build_conversation(question, 1024);
        if (strlen(question) == 0) {
                    ERROR_LOG("输入内容无效");
                    continue; 
                }
                DEBUG_LOG("问题内容长度：%zu字节", strlen(question));
        INFO_LOG("正在启动请求...");

        // 执行标准API请求（绑定流式回调）
        success = DS_SendStandardRequest(api_key, question, mode, stream_callback);
        
        if (success)
        { 
            printf("/n/n");
            break;  // 成功则退出重试循环
        }
        
        // 计算指数退避时间（1, 2, 4 秒...）
        int delay = BASE_RETRY_DELAY * (1 << retries);  // 位运算实现2的幂次
        ERROR_LOG("请求失败，%d秒后重试 (%d/%d)...", delay, retries+1, MAX_RETRIES);
        
        /* 可中断的等待循环：
         * 1. 每秒检查中断状态
         * 2. 支持即时响应用户Ctrl+C
         * 3. 精确控制总等待时间
         */
        for (int i = 0; i < delay && !g_interrupted; ++i) {
            sleep(1);  // 最小等待单位1秒
        }
    } while (++retries < MAX_RETRIES && !g_interrupted);  // 双条件控制循环

    // 返回最终状态（成功/重试耗尽/用户中断）
    return success;
}

  // 信号处理函数
 /**
  * @brief 信号处理函数（SIGINT/SIGTERM）
  * @param sig 接收到的信号编号
  * 
  * 功能特性：
  * 1. 设置原子中断标志 g_interrupted
  * 2. 线程安全的信号处理（仅使用 async-signal-safe 函数）
  * 3. 即时响应用户中断请求
  * 
  * 注意事项：
  * - 使用 sig_atomic_t 保证原子操作
  * - 避免在信号处理函数中进行复杂操作
  */
 static void handle_signal(int sig) {
    g_interrupted = true;  // 设置原子中断标志（保证多线程可见性）
    fprintf(stderr, "\n[系统] 正在终止请求...\n");  // 用户可见的中断提示
}

 // 初始化环境
 /**
  * @brief 系统环境初始化函数
  * @param ca_path [out] 证书路径指针的指针
  * @return bool 初始化是否成功
  * 
  * 功能流程：
  * 1. 注册信号处理器
  * 2. 检测SSL证书可用性
  * 3. 初始化HTTP客户端
  * 4. 设置网络超时参数
  * 
  * 安全机制：
  * - 自动降级非安全模式（证书不可用时）
  * - 双重HTTP初始化保证兼容性
  */
 static bool setup_environment(const char** ca_path) {
    // 注册中断信号处理器（SIGINT=Ctrl+C, SIGTERM=终止信号）
    signal(SIGINT, handle_signal);
    signal(SIGTERM, handle_signal);

    // 检测系统证书路径（Linux标准证书位置）
    *ca_path = DEEPSEEK_API_CA_PATH;
    if (access(*ca_path, R_OK)) {
        ERROR_LOG("证书不可访问: %s", *ca_path);
        *ca_path = NULL; // 进入非安全模式
        ERROR_LOG("警告：已禁用SSL验证！");
    }

    /* 调试专用初始化（生产环境应移除）
     * 此处可能用于绕过证书验证进行调试
     * 注意：实际代码中不应连续调用两次初始化 */
    //HTTP_ClientInit(NULL); // 仅用于调试，生产环境勿用

    // 正式初始化HTTP客户端（根据证书状态决定安全模式）
    if (!HTTP_ClientInit(*ca_path)) {
        ERROR_LOG("HTTP初始化失败");
        return false;
    }
    HTTP_SetTimeout(60);  // 设置全局网络超时（单位：秒）
    return true;
}
 
// 构造对话内容
 /**
  * @brief 对话内容生成器
  * @param buffer 输出缓冲区（需预先分配内存）
  * @param size 缓冲区总大小（字节数）
  * 
  * 功能说明：
  * 1. 预定义对话问题列表
  * 2. 安全填充缓冲区（防溢出）
  * 3. 自动添加换行分隔符
  * 
  * 注意事项：
  * - 问题列表以 NULL 指针结尾
  * - 使用 snprintf 保证安全写入
  * - 支持动态扩展问题列表
  */
 static void build_conversation(char* buffer, size_t size) {
    // 预设问题列表（必须以 NULL 结尾）
    // const char* questions[] = {
    //     "你好",          // 示例问题1
    //     "你叫什么名字？", // 示例问题2
    //     NULL             // 列表终止标记
    // };
    //memset(buffer, 0, size);
    printf("请输入问题（输入 exit 退出）：");  // 添加退出提示
    if (!fgets(buffer, size, stdin)) {
        strncpy(buffer, "exit", 4);  // 输入错误视为退出
        return;
    }
    // 安全截断换行符
    char* newline = strchr(buffer, '\n');
    if (newline) *newline = '\0';
    if (strcmp(buffer, "exit") == 0) {
        g_interrupted = true;  // 设置中断标志
    }
}

 void deepseek_talk_init(void)
 {
    // 第一阶段：环境初始化
    const char* ca_path;
    if (!setup_environment(&ca_path)) return ;
    INFO_LOG("运行环境初始化完成 (%s)", ca_path ? "安全模式" : "非安全模式");
     // 第二阶段：API密钥校验
     const char* api_key = DEEPSEEK_API_KEY;  // 从编译环境获取密钥
    if (!api_key  ) { 
        ERROR_LOG("无效API密钥");
        HTTP_ClientCleanup();
        return ;
    }
    DEBUG_LOG("API密钥格式校验通过");

}
int deepseek_talk(void)
{
    printf("🔄 ");  // 初始化旋转图标
    fflush(stdout); // 立即显示状态图标
    bool success;
    char question[1024]={0};  // 问题缓冲区（可调整大小）
    while(!g_interrupted) {  // 替换原来的 while(1)
        memset(question, 0, 1024);
        success= execute_request_with_retry(DEEPSEEK_API_KEY, question,DEEPSEEK_MODE);
        printf("\n\n");  
        if (success) {
            INFO_LOG("请求成功完成");
            // // 添加退出选项提示
            // printf("继续提问？ (y/n) ");
            // fflush(stdout);
            // char choice = getchar();
            // if (tolower(choice) != 'y') {
            //     while ((choice = getchar()) != '\n' && choice != EOF); // 清空输入缓冲区
            //     break;
            // }
            // while ((choice = getchar()) != '\n' && choice != EOF); // 清空输入缓冲区
        } else if (g_interrupted) {
            ERROR_LOG("请求被用户中断");
            break;
        } else {
            ERROR_LOG("请求失败");
            // ... existing error handling ...
        }
    }
    
    HTTP_ClientCleanup();  
    INFO_LOG("资源清理完成");
    
    return EXIT_SUCCESS;  // 统一返回成功状态
}
